package com.itheima.app.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.itheima.app.interceptor.UserHolder;
import com.itheima.autoconfig.face.AipFaceTemplate;
import com.itheima.autoconfig.huanxin.HuanXinTemplate;
import com.itheima.autoconfig.oss.OssTemplate;
import com.itheima.autoconfig.sms.SmsTemplate;
import com.itheima.domain.db.Log;
import com.itheima.domain.db.User;
import com.itheima.domain.db.UserInfo;
import com.itheima.service.db.UserInfoService;
import com.itheima.service.db.UserService;
import com.itheima.util.ConstantUtil;
import com.itheima.util.JwtUtil;
import com.itheima.vo.UserInfoVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service//spring的
public class UserManager {

    //远程调用service
    @Reference//阿里的
    private UserService userService;

    @Reference
    private UserInfoService userInfoService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Autowired
    private SmsTemplate smsTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private AipFaceTemplate aipFaceTemplate;

    @Autowired
    private OssTemplate ossTemplate;

    //保存用户
    public Long save(User user) {

        //密码加密
        user.setPassword(SecureUtil.md5(user.getPassword()));

        //调用service保存
        Long userId = userService.save(user);

        return userId;
    }

    //根据手机号查询用户信息
    public User findByPhone(String phone) {
        return userService.findByPhone(phone);
    }

    //发送手机验证码
    public void sendSmsCode(String phone) {
        //1. 生成验证码
        //String code = RandomUtil.randomNumbers(6);
        String code = "123456";

        //2. 发送验证码
        //smsTemplate.sendSms(phone, code);
        System.out.println(code);

        //3. 保存验证码
        stringRedisTemplate.opsForValue().set(ConstantUtil.SMS_CODE + phone, code, Duration.ofMinutes(5));
    }

    //登录注册
    public Map<String, Object> loginOrReg(String phone, String verificationCode) {
        //1. 校验验证码
        String codeFromRedis = stringRedisTemplate.opsForValue().get(ConstantUtil.SMS_CODE + phone);
        if (!StringUtils.equals(codeFromRedis, verificationCode)) {
            //比对失败,直接返回错误信息
            throw new RuntimeException("验证码错误");
        }

        //2.比对成功
        stringRedisTemplate.delete(ConstantUtil.SMS_CODE + phone);//删除验证码

        //3. 查询手机号
        User user = userService.findByPhone(phone);
        boolean isNew;
        String type = "";
        if (user != null) {
            //当前用户存在,登录
            isNew = false;
            type = "0101";
        } else {
            //当前用户不存在,注册
            user = new User();
            user.setPhone(phone);
            user.setPassword(SecureUtil.md5(ConstantUtil.INIT_PASSWORD));
            Long userId = userService.save(user);

            user.setId(userId);

            //新用户
            isNew = true;
            type = "0102";

            //向环信中保存当前用户
            huanXinTemplate.register(userId);
        }

        //创建Log对象
        Log log = new Log();
        log.setUserId(user.getId());
        log.setType(type);
        log.setLogTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        log.setPlace("北京");//可以根据userId去Location查询
        log.setEquipment("小米");

        //向MQ投递日志
        rocketMQTemplate.convertAndSend("tanhua-log", log);

        //4. 创建token
        Map<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("id", user.getId());
        tokenMap.put("phone", user.getPhone());
        String token = JwtUtil.createToken(tokenMap);

        //进行判断，冻结信息表中是否有冻结时间和冻结范围（冻结范围需要是冻结登录）
        //从redis中拿到冻结时间标识码
        String freezeTime = stringRedisTemplate.opsForValue().get(ConstantUtil.Freeze_Time + user.getId());
        //从redis中拿到冻结范围标识码
        String freezeRange = stringRedisTemplate.opsForValue().get(ConstantUtil.Freeze_Range + user.getId());
        //判断是否要保存token到redis中
        if (StringUtils.isEmpty(freezeTime)&&!StringUtils.equals(freezeRange,"1")) {
            //将token保存到redis
            stringRedisTemplate.opsForValue().set(ConstantUtil.USER_TOKEN + token, "1", Duration.ofDays(30));
        }



        //把token的有效时间设置为2小时
        //方案一: 每次客户端访问服务器的时候,服务器要进行token续期(重新颁发token,或者修改时间), 还要将修改之后的token再返回去,这时候前端需要提供一个接受token的接口
        //方案二: 用户登录成功之后,要将当前token存入redis(设置有效期), 每次客户端访问服务器的时候,我们还需要校验redis中是否还有这个token,如果有的话,将时长续期


        //5. 返回结果map
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", token);
        resultMap.put("isNew", isNew);
        return resultMap;
    }

    //完善个人基本信息
    public void saveUserBaseInfo(UserInfo userInfo) {
        userInfoService.save(userInfo);
    }

    //完善头像基本信息
    public void saveUserHeaderInfo(Long userId, MultipartFile headPhoto) throws IOException {
        //1. 先人脸检查
        boolean detect = aipFaceTemplate.detect(headPhoto.getBytes());
        System.out.println("---------------人脸识别结果:" + detect);
        if (!detect) {
            throw new RuntimeException("人脸识别失败");
        }

        //2. 再进行头像上传
        String filePath = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
        System.out.println("---------------人脸路径:" + filePath);

        //3. 更新头像地址
        UserInfo userInfo = new UserInfo();//update avatar=?,coverPic=? where id = ?
        userInfo.setAvatar(filePath);
        userInfo.setCoverPic(filePath);
        userInfo.setId(userId);

        userInfoService.update(userInfo);
    }

    //根据userId查询用户信息
    public UserInfoVo findByUserId(Long userId) {
        UserInfo userInfo = userInfoService.findByUserId(userId);

        //给userInfoVo赋值
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtil.copyProperties(userInfo, userInfoVo);//属性名称和类型得完全一致
        userInfoVo.setAge(userInfo.getAge() + "");

        return userInfoVo;
    }

    //更新个人基本信息
    public void updateUserBaseInfo(UserInfo userInfo) {
        userInfoService.update(userInfo);
    }

    //校验验证码
    public Map<String, Boolean> checkVerificationCode(String verificationCode, String phone) {

        boolean b = true;

        //1. 校验验证码
        //判断比较，输入的验证码与Redis中保存的验证码是否相等
        String codeFromRedis = stringRedisTemplate.opsForValue().get(ConstantUtil.SMS_CODE + phone);
        if (!StringUtils.equals(codeFromRedis, verificationCode)) {
            //比对失败,直接返回错误信息
            b = false;
        }
        //2.比对成功 删除redis中的验证码
        stringRedisTemplate.delete(ConstantUtil.SMS_CODE + phone);//删除验证码

        HashMap<String, Boolean> map = new HashMap<>();

        map.put("verification", b);

        return map;
    }

    //保存
    public void updatePhone(String phone) {
        //获取当前用户
        User user1 = UserHolder.get();
        //获取修改的手机号
        User user = userService.findByPhone(phone);
        //根据获取修改的手机号，进行判断数据库中是否存在
        if (user == null) {
            //修改当前用户的手机号
            user1.setPhone(phone);
            //当前用户id，将输入修改的手机号保存到该id中
            userService.update(user1);
        }else {
            throw new RuntimeException("手机号已存在！");
        }
    }
}

